package com.rundow.common.sdk.listener;

import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSON;
import com.rundow.common.base.bean.driver.DriverConfiguration;
import com.rundow.common.base.bean.driver.DriverMetadata;
import com.rundow.common.base.constant.Common;
import com.rundow.common.base.constant.CommonConstant;
import com.rundow.common.base.model.*;
import com.rundow.common.base.model.event.DriverMetaEvent;
import com.rundow.common.base.utils.JsonUtil;
import com.rundow.common.sdk.bean.driver.ContainerContext;
import com.rundow.common.sdk.bean.driver.DriverContext;
import com.rundow.common.sdk.init.ServiceContainerRegister;
import com.rundow.common.sdk.service.DriverMetadataService;
import com.rundow.common.sdk.service.DriverService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Slf4j
@Component
public class DriverMetadataListener {

    @Resource
    private DriverService driverService;
    @Resource
    private DriverMetadataService driverMetadataService;

    @Resource
    private ContainerContext containerContext;

    @Resource
    private ServiceContainerRegister serviceContainerRegister;

    @Async
    @EventListener
    public void driverConfigurationReceive(DriverMetaEvent driverMetaEvent) {
        final DriverConfiguration driverConfiguration = driverMetaEvent.getDriverConfiguration();
        final String driverName = driverMetaEvent.getDriverName();
        switch (driverConfiguration.getType()) {
            case Common.Driver.Type.DRIVER:
                configurationDriver(driverName, driverConfiguration);
                break;
            case Common.Driver.Type.PROFILE:
                configurationProfile(driverName,driverConfiguration);
                break;
            case Common.Driver.Type.DEVICE:
                configurationDevice(driverName,driverConfiguration);
                break;
            case Common.Driver.Type.POINT:
                configurationPoint(driverName,driverConfiguration);
                break;
            case Common.Driver.Type.DRIVER_INFO:
                configurationDriverInfo(driverName,driverConfiguration);
                break;
            case Common.Driver.Type.POINT_INFO:
                configurationPointInfo(driverName,driverConfiguration);
                break;
            default:
                break;
        }

    }


    /**
     * 配置 driver
     *
     * @param driverConfiguration DriverConfiguration
     */
    private void configurationDriver(String driverName, DriverConfiguration driverConfiguration) {
        if (!CommonConstant.Response.OK.equals(driverConfiguration.getResponse())) {
            driverService.close("The driver initialization failed: {}", driverConfiguration.getResponse());
        }
        final DriverContext driverContext = containerContext.factoryDriverContext(driverName);

        switch (driverConfiguration.getCommand()) {
            case CommonConstant.Driver.Event.DRIVER_HANDSHAKE_BACK:
                driverContext.setDriverStatus(CommonConstant.Status.REGISTERING);
                break;
            case CommonConstant.Driver.Event.DRIVER_REGISTER_BACK:
                driverContext.setDriverStatus(CommonConstant.Status.ONLINE);
                break;
            case CommonConstant.Driver.Event.DRIVER_METADATA_SYNC_BACK:
                DriverMetadata driverMetadata = Convert.convert(DriverMetadata.class, driverConfiguration.getContent());
                driverContext.setDriverMetadata(driverMetadata);
                driverMetadata
                        .getDriverAttributeMap()
                        .values()
                        .forEach(driverAttribute -> log.info("Syncing driver attribute[{}] metadata: {}", driverAttribute.getDisplayName(), JsonUtil.toJsonString(driverAttribute)));
                driverMetadata
                        .getPointAttributeMap()
                        .values()
                        .forEach(pointAttribute -> log.info("Syncing point attribute[{}] metadata: {}", pointAttribute.getDisplayName(), JsonUtil.toJsonString(pointAttribute)));
                driverMetadata
                        .getDeviceMap()
                        .values()
                        .forEach(device -> log.info("Syncing device[{}] metadata: {}", device.getName(), JsonUtil.toJsonString(device)));
                serviceContainerRegister.register(driverName);
                log.info("The metadata synced successfully");
                break;
            default:
                break;
        }
    }

    /**
     * 配置 driver profile
     *
     * @param driverConfiguration DriverConfiguration
     */
    private void configurationProfile(String driverName,DriverConfiguration driverConfiguration) {
        Profile profile = Convert.convert(Profile.class, driverConfiguration.getContent());
        if (Common.Driver.Profile.ADD.equals(driverConfiguration.getCommand()) || Common.Driver.Profile.UPDATE.equals(driverConfiguration.getCommand())) {
            log.info("Upsert profile \n{}", JSON.toJSONString(profile, true));
            driverMetadataService.upsertProfile(driverName,profile);
        } else if (Common.Driver.Profile.DELETE.equals(driverConfiguration.getCommand())) {
            log.info("Delete profile {}", profile.getName());
            driverMetadataService.deleteProfile(driverName,profile.getId());
        }
    }

    /**
     * 配置 driver device
     *
     * @param driverConfiguration DriverConfiguration
     */
    private void configurationDevice(String driverName,DriverConfiguration driverConfiguration) {
        Device device = Convert.convert(Device.class, driverConfiguration.getContent());
        if (Common.Driver.Device.ADD.equals(driverConfiguration.getCommand()) || Common.Driver.Device.UPDATE.equals(driverConfiguration.getCommand())) {
            log.info("Upsert device \n{}", JSON.toJSONString(device, true));
            driverMetadataService.upsertDevice(driverName,device);
        } else if (Common.Driver.Device.DELETE.equals(driverConfiguration.getCommand())) {
            log.info("Delete device {}", device.getName());
            driverMetadataService.deleteDevice(driverName,device.getId());
        }
    }

    /**
     * 配置 driver point
     *
     * @param driverConfiguration DriverConfiguration
     */
    private void configurationPoint(String driverName,DriverConfiguration driverConfiguration) {
        Point point = Convert.convert(Point.class, driverConfiguration.getContent());
        if (Common.Driver.Point.ADD.equals(driverConfiguration.getCommand()) || Common.Driver.Point.UPDATE.equals(driverConfiguration.getCommand())) {
            log.info("Upsert point \n{}", JSON.toJSONString(point, true));
            driverMetadataService.upsertPoint(driverName,point);
        } else if (Common.Driver.Point.DELETE.equals(driverConfiguration.getCommand())) {
            log.info("Delete point {}", point.getName());
          //  driverMetadataService.deletePoint(driverName,point.getProfileId(), point.getId());
        }
    }

    /**
     * 配置 driver info
     *
     * @param driverConfiguration DriverConfiguration
     */
    private void configurationDriverInfo(String driverName,DriverConfiguration driverConfiguration) {
        DriverInfo driverInfo = Convert.convert(DriverInfo.class, driverConfiguration.getContent());
        if (Common.Driver.DriverInfo.ADD.equals(driverConfiguration.getCommand()) || Common.Driver.DriverInfo.UPDATE.equals(driverConfiguration.getCommand())) {
            log.info("Upsert driver info \n{}", JSON.toJSONString(driverInfo, true));
            driverMetadataService.upsertDriverInfo(driverName,driverInfo);
        } else if (Common.Driver.DriverInfo.DELETE.equals(driverConfiguration.getCommand())) {
            log.info("Delete driver info {}", driverInfo);
          //  driverMetadataService.deleteDriverInfo(driverName,driverInfo.getDeviceId(), driverInfo.getDriverAttributeId());
        }
    }

    /**
     * 配置 driver point info
     *
     * @param driverConfiguration DriverConfiguration
     */
    private void configurationPointInfo(String driverName,DriverConfiguration driverConfiguration) {
        PointInfo pointInfo = Convert.convert(PointInfo.class, driverConfiguration.getContent());
        if (Common.Driver.PointInfo.ADD.equals(driverConfiguration.getCommand()) || Common.Driver.PointInfo.UPDATE.equals(driverConfiguration.getCommand())) {
            log.info("Upsert point info \n{}", JSON.toJSONString(pointInfo, true));
            driverMetadataService.upsertPointInfo(driverName,pointInfo);
        } else if (Common.Driver.PointInfo.DELETE.equals(driverConfiguration.getCommand())) {
            log.info("Delete point info {}", pointInfo);
            driverMetadataService.deletePointInfo(driverName,pointInfo.getPointId(), pointInfo.getId(), pointInfo.getPointAttributeId());
        }
    }
}
